#pragma once

#include "Sock.hpp"
#include "Log.hpp"
#include <string>
#include <functional>
#include <sys/types.h>
#include <unistd.h>

class HttpServer
{
    using func_t = std::function<void(int)>;

public:
    HttpServer(func_t func, uint16_t port, const std::string &ip = "0.0.0.0")
        : _func(func), _port(port), _ip(ip), _listenSock(-1)
    { }

    // 初始化http服务器
    void init()
    {
        // 1.创建监听套接字
        _listenSock = ns_sock::Sock::Socket();   // 创建套接字
        if(_listenSock < 0)
        {
            exit(2);
        }

        // 绑定端口号
        if(ns_sock::Sock::Bind(_listenSock, _ip, _port) < 0)
        {
            // 绑定失败
            exit(3);
        }

        // 设置监听状态
        if(ns_sock::Sock::Listen(_listenSock, 20) < 0)
        {
            // 监听失败
            exit(4);
        }
    }

    // 启动http服务器（开始运行）
    void start()
    {
        // 0. 服务区进是常驻系统的，死循环不退出
        while(true)
        {
            std::string cli_ip;   // 客户端ip
            uint16_t cli_port;       // 客户端port

            // 1. 接受客户端的连接
            int cli_sock = ns_sock::Sock::Accept(_listenSock, &cli_ip, &cli_port);
            if(cli_sock < 0)
            {
                // 接受客户端连接失败，直接进入下一轮循环，重新接收连接
                continue;
            }

            // 2. 创建子进程，运行http服务器代码
            pid_t id = fork();   
            if(id == 0)
            {
                // 子进程代码
                close(_listenSock);
                _func(cli_sock);
                close(cli_sock);
                exit(0);
            }

            // 关闭不需要的文件描述符
            close(cli_sock);
        }
    }

    // 析构函数
    ~HttpServer()
    {
        // 如果创建了监听文件描述符，就将其关闭
        if(_listenSock >= 0)
        {
            close(_listenSock);
        }
    }

private:
    func_t _func;       // 服务端执行的方法
    uint16_t _port;     // 端口号
    std::string _ip;    // ip地址
    int _listenSock;    // socket套接字文件描述符
};